﻿using DeHeng_Mes;
using DeHeng_Mes.Business;
using DeHeng_Mes.Constant;
using DeHeng_Mes.Model;
using DeHeng_Mes.Model.PlcModel;
using DeHeng_Mes.Utils;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using S7.Net;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Xml.Linq;
using RichTextBox = System.Windows.Forms.RichTextBox;

/// <summary>
/// PLC交互帮助类
/// </summary>
public class PlcConnectionManager
{

    #region 线程事件变量
    Task _connectTask;
    private CancellationTokenSource _cts;

    #endregion

    #region PLC参数变量

    public static List<PlcConfigModel> plcContainer { get; set; }

    #endregion

    #region 其他成员

    #endregion

    /// <summary>
    /// PLC通讯线程管理器
    /// </summary>
    /// <param name="uiForm"></param>
    public PlcConnectionManager(List<PlcConfigModel> plcConfigs)
    {
        //初始化PLC配置信息
        plcContainer = plcConfigs;
    }




    /// <summary>
    /// 启动连接PLC线程
    /// </summary>
    /// <returns></returns>
    public void ConnectToPlc()
    {
        _cts = new CancellationTokenSource();
        var token = _cts.Token;
        foreach (var item in plcContainer)
        {
            _connectTask = Task.Run(async () =>
            {
                try
                {
                    Plc plc = item.plc;
                    Tools.DeviceLogText(item.nick + "正在连接........");
                    await plc.OpenAsync(token);
                    item.isConnected = true;
                    Tools.DeviceLogText(item.nick + "已连接成功");
                    //启动心跳线程
                    item.heartBeatTask = Task.Run(() => sendHeartBeat(item, token));
                }
                catch (Exception ex)
                {
                    //打印失败日志
                    Tools.DeviceLogTextError(item.nick + ":" + ex.Message);
                    await Task.Delay(item.heartBeat);
                    //启动重连线程
                    ReconnectToPlc(item, token);
                }
            }, token);
        }
    }

    /// <summary>
    /// 心跳线程
    /// </summary>
    /// <param name="plcConfig"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    private async Task sendHeartBeat(PlcConfigModel plcConfig, CancellationToken token)
    {
        Tools.DeviceLogText($"启动：{plcConfig.nick} 心跳线程");
        while (plcConfig.isConnected && !token.IsCancellationRequested)
        {
            try
            {
                bool beat = false;
                while (true)
                {
                    plcConfig.plc.WriteBit(DataType.DataBlock, 6011, 0, 1, beat);
                    beat = !beat;
                    await Task.Delay(60000);
                }
            }
            catch (Exception ex)
            {
                plcConfig.isConnected = false;
                Tools.DeviceLogTextError("发送心跳包：" + plcConfig.nick + "失败:" + ex.Message);
                await Task.Delay(plcConfig.heartBeat);
                //启动重连线程
                ReconnectToPlc(plcConfig, token);
                break;
            }
        }
    }

    /// <summary>
    /// 重连线程
    /// </summary>
    /// <param name="plcConfig"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    private async void ReconnectToPlc(PlcConfigModel plcConfig, CancellationToken token)
    {
        Tools.DeviceLogText($"启动：{plcConfig.nick} 重连线程");
        bool logIsOut = false;
        while (!plcConfig.isConnected && !token.IsCancellationRequested)
        {
            try
            {
                plcConfig.plc.Open();
                plcConfig.isConnected = true;
                //启动心跳线程
                plcConfig.heartBeatTask = Task.Run(() => sendHeartBeat(plcConfig, token));
                break;
            }
            catch (Exception ex)
            {
                plcConfig.isConnected = false;
                if (!logIsOut)
                    Tools.DeviceLogTextError($"{plcConfig.nick}重连线程启动失败，原因是{ex.Message}");
                logIsOut = true;
            }
            await Task.Delay(plcConfig.retryInterval);
        }
    }
    #region 自定义方法

    #endregion

}